/*
 * Project Name demo
 * File Name IDUtil
 * Package Name com.huxiaosu.demo.socketio.util
 * Create Time 2023/1/31
 * Create by name：liujie
 */
package com.huxiaosu.demo.socketio.util;

import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Description
 *
 * @ClassName: IDUtil
 * @author: liujie
 * @date: 2023/1/31 14:39
 */
public class IDUtil {
    private static final int CLUSTER_SEQ = Integer.parseInt(System.getProperty("cluster.seq", "0"));

    private static final char[] SEED0 = "0123456789abcdefghijklmnopqrstuv".toCharArray();

    private static final char[] SEED1 = "wxyzABCDEFGHIJKLMNOPQRSTUVWXYZuv".toCharArray();

    private static final AtomicInteger COUNTER = new AtomicInteger(new Random().nextInt(Integer.MAX_VALUE));

    private static final Integer DEFAULT_LENGTH = 16;


    /**
     * Description：生成数字ID，保证一定条件下的全局唯一性。
     * 在1024台服务器以下的集群环境、单台机器每毫秒调用不超过4194304次的情况下1天内生成的ID不重复
     *
     * @return long
     * @author name：
     */
    public static long numericID() {
        int count = COUNTER.incrementAndGet();
        int seq = count & 0x1F;
        seq = ((seq & 15) << 1) | (seq >>> 4);
        long x = ((long) seq) << 58 | (CLUSTER_SEQ & 0x3FFL) << 48;
        x |= (System.currentTimeMillis() << 42 >>> 16);
        x |= (count >>> 5);
        long t = x & (-1L >>> 16);
        t = ((t & ((1L << seq) - 1)) << (48 - seq)) | (t >>> seq);
        x = ((x >>> 48) << 48) | t;
        return x;
    }

    /**
     * Description：生成16位字符的唯一字符串
     * 在公元10000年前、1024台服务器以下的集群环境、单台机器每毫秒调用不超过4194304次的情况下生成的ID不重复。
     *
     * @return String
     * @author name：lljqiu
     */
    public static String randomID() {
        int count = COUNTER.incrementAndGet() & 0x3FFFFF;
        int seq = count & 0x3F;
        seq = ((seq & 15) << 2) | (seq >>> 4);
        int x = ((CLUSTER_SEQ & 0x3FF) << 6) | seq;
        long y = System.currentTimeMillis() << 16;
        y |= (count >>> 6);
        y = (y << (64 - seq)) | (y >>> seq);

        Random random = new Random();
        char[] chars = new char[16];
        for (int i = 0; i < 12; i++) {
            int k = (int) (y & 31);
            chars[i] = random.nextBoolean() ? SEED0[k] : SEED1[k];
            y >>>= 5;
        }
        x = (x << 4) | (int) y;
        for (int i = 0; i < 4; i++) {
            int k = (x & 31);
            chars[12 + i] = (random.nextBoolean() ? SEED0[k] : SEED1[k]);
            x >>>= 5;
        }
        return new String(chars);
    }

    /**
     * Description：生成指定长度的唯一字符串，至少16字符
     *
     * @param len
     * @return String
     * @author name：lljqiu
     */
    public static String randomID(int len) {
        String str = randomID();
        if (len <= DEFAULT_LENGTH) {
            return str;
        }
        char[] chars = new char[len];
        System.arraycopy(str.toCharArray(), 0, chars, 0, 16);
        Random random = new Random();
        int remain = len - 16;
        for (int i = 0; i < remain; i++) {
            int idx = random.nextInt(32);
            chars[16 + i] = random.nextBoolean() ? SEED0[idx] : SEED1[idx];
        }
        return new String(chars);
    }

    public static String randomNumberId(int len) {
        int count = COUNTER.incrementAndGet();
        int seq = count & 0x1F;
        seq = ((seq & 15) << 1) | (seq >>> 4);
        long x = ((long) seq) << 58 | (CLUSTER_SEQ & 0x3FFL) << 48;
        x |= (System.currentTimeMillis() << 42 >>> 16);
        x |= (count >>> 5);
        return String.valueOf(x).substring(0, len);
    }

}